package pro.cherish.smartfile.config.swagger.threadpool;

import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.lang.reflect.Method;
import java.util.concurrent.Executor;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * @author 创建人：lys
 * @version 版本号：V1.0
 * <p>
 * ***************************修订记录************************************
 * 2020-5-29 lys 创建该类功能。
 * **********************************************************************
 * </p>
 * @ClassName 类名：ThreadPoolConfig
 * @Description 功能说明：@Async使用的任务执行线程池默认为该线程池
 * <p>

 * </p>
 * **********************************************************************
 * @date 创建日期： 2020-5-29 
 */
@Configuration
@Slf4j
public class ThreadPoolConfig implements AsyncConfigurer {


	/**
	 * Set the ThreadPoolExecutor's core pool size.
	 */
	// 处理器的核心数
	private static int coreNum = Runtime.getRuntime().availableProcessors();
	// IO密集
	private static final int CORE_POOL_SIZE = coreNum * 2;
	/**
	 * Set the ThreadPoolExecutor's maximum pool size.
	 */
	private static final int MAX_POOL_SIZE = coreNum * 2 * 2;
	/**
	 * Set the capacity for the ThreadPoolExecutor's BlockingQueue.
	 */
	private static final int QUEUE_CAPACITY = coreNum * 2 * 2;

	/**
	 * 通过重写getAsyncExecutor方法，制定默认的任务执行由该方法产生
	 * 配置类实现AsyncConfigurer接口并重写getAsyncExcutor方法，并返回一个ThreadPoolTaskExevutor
	 * 获得了一个基于线程池的TaskExecutor
	 */
	@Override
	public Executor getAsyncExecutor() {
		ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
		taskExecutor.setThreadGroupName("服务Async任务线程组");
		taskExecutor.setThreadNamePrefix("smart-file-Default-Executor-");
		taskExecutor.setCorePoolSize(CORE_POOL_SIZE);
		taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
		taskExecutor.setQueueCapacity(QUEUE_CAPACITY);
		taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
		taskExecutor.initialize();
		return taskExecutor;
	}

	@Override
	public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
		return new CustomizeAsyncUncaughtExceptionHandler();
	}

	/**
	 * 自定义异常捕获的处理方式（对于无返回值的方法）
	 * 备注：有方返回值（future）使用future.get()方法包装一层try catch
	 */
	public class CustomizeAsyncUncaughtExceptionHandler extends SimpleAsyncUncaughtExceptionHandler {
		public CustomizeAsyncUncaughtExceptionHandler() {
			super();
		}

		@Override
		public void handleUncaughtException(Throwable ex, Method method, Object... params) {
			log.error("默认线程池处理未捕获到的异常");
			log.error("class#method: " + method.getDeclaringClass().getName() + "#" + method.getName());
			log.error("type        : " + ex.getClass().getName());
			log.error("exception   : " + ex.getMessage());
			super.handleUncaughtException(ex, method, params);
		}
	}

	/**
	 *  自定义线程池拒绝策略
	 */
	public class BizRejectedExecutionHandler implements RejectedExecutionHandler {
		BizRejectedExecutionHandler() {
		}

		@Override
		public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
			log.error("线程池满了，任务未执行并且被抛弃,抛出异常,其中丢失的任务为{}", r.toString());
			log.info("当前使用的线程池的执行器配置为,corePoolSize={},maximumPoolSize ={},queueSize ={},rejectedExecutorHandler={}", e.getCorePoolSize(), e.getMaximumPoolSize(), e.getQueue().size(), e.getRejectedExecutionHandler());
			throw new RejectedExecutionException("Task " + r.toString() +
					" rejected from " +
					e.toString());
			// todo 告警，
		}
	}

	/**
	 * 任务执行器
	 * @Return java.util.concurrent.Executor
	 * @Author lys
	 * @Date 2020-5-29 11:23
	 */
	@Bean("bizTaskExecutor")
	public Executor bizTaskExecutor() {
		ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor();
		taskExecutor.setThreadGroupName("(Biz)任务线程组");
		taskExecutor.setThreadNamePrefix("biz-Executor-");
		taskExecutor.setCorePoolSize(CORE_POOL_SIZE);
		taskExecutor.setMaxPoolSize(MAX_POOL_SIZE);
		taskExecutor.setQueueCapacity(QUEUE_CAPACITY);
		// 此处选择的拒绝策略为记录日志不处理（不使用CallerRunsPolicy，调用者执行）
		taskExecutor.setRejectedExecutionHandler(new BizRejectedExecutionHandler());
		taskExecutor.initialize();
		return taskExecutor;
	}
}
